﻿// *****************************************************************************
// **                   Ladenius MediaCenter TVSeries                         **
// ** ----------------------------------------------------------------------- **
// ** (c) 2008 by Jurjen Ladenius                                             **
// *****************************************************************************

#region Using directives
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using Ladenius.TheTVDB.Utilities;
using Ladenius.TheTVDB.Entities;
using System.Web;
using Ladenius.TheTVDB.Business;
#endregion

namespace Ladenius.TheTVDB.Dao {
    /// <summary>
    /// Provides access to the TheTVDB XML api
    /// </summary>
    /// <seealso cref="http://thetvdb.com/wiki/index.php?title=Programmers_API">Programmers API</seealso>
    internal static class XMLRequester {

        #region Mirror
        /// <summary>
        /// Gets the mirrors.
        /// </summary>
        /// <returns>a list of mirrors</returns>
        internal static List<Mirror> GetMirrors() {
            List<Mirror> result = new List<Mirror>();
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load("http://www.thetvdb.com/api/" + Settings.TheTVDBApiKey + "/mirrors.xml");
            foreach (XmlNode node in xmlDocument.SelectNodes("//Mirrors/Mirror")) {
                result.Add(new Mirror() { 
                    ID = GetNodeInt(node, "id"), 
                    MirrorPath = GetNodeText(node, "mirrorpath"), 
                    TypeMask = (TypeMaskType)Convert.ToInt32(GetNodeText(node, "typemask")) 
                });
            }
            return result;
        }
        #endregion

        #region Language
        /// <summary>
        /// Gets the languages.
        /// </summary>
        /// <returns>a list of languages</returns>
        internal static List<Language> GetLanguages() {
            List<Language> result = new List<Language>();
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load("http://www.thetvdb.com/api/" + Settings.TheTVDBApiKey + "/languages.xml");
            foreach (XmlNode node in xmlDocument.SelectNodes("//Languages/Language")) {
                result.Add(new Language() { 
                       ID = GetNodeInt(node, "id"), 
                       Name = GetNodeText(node, "name"), 
                       Abbreviation = GetNodeText(node, "abbreviation") 
                });
            }
            return result;
        }
        #endregion

        #region Series
        internal static List<Series> FindSeries(string name) {
            Mirror mirror = MirrorHome.Get_Data();
            List<Series> result = new List<Series>();
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(mirror.MirrorPath + "/api/GetSeries.php?seriesname=" + HttpUtility.UrlEncode(name));
            foreach (XmlNode node in xmlDocument.SelectNodes("//Data/Series")) {
                result.Add(ParseSeriesNode(node));
            }
            return result;
        }
        /// <summary>
        /// Parses the series node.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <returns></returns>
        private static Series ParseSeriesNode(XmlNode node) {
            char[] splitChar = new char[] { '|' };
            DateTime firstAired;
            DateTime lastUpdated;
            if (!DateTime.TryParse(GetNodeText(node, "FirstAired"), out firstAired)) firstAired = DateTime.MinValue;
            if (!DateTime.TryParse(GetNodeText(node, "lastupdated"), out lastUpdated)) lastUpdated = DateTime.MinValue;
            return new Series() {
                ID = GetNodeInt(node, "id"),
                Actors = new List<string>(GetNodeText(node, "Actors").Split(splitChar, StringSplitOptions.RemoveEmptyEntries)),
                Airs_DayOfWeek = GetNodeText(node, "Airs_DayOfWeek"),
                Airs_Time = GetNodeText(node, "Airs_Time"),
                ContentRating = GetNodeText(node, "ContentRating"),
                FirstAired = firstAired,
                Genre = new List<string>(GetNodeText(node, "Genre").Split(splitChar, StringSplitOptions.RemoveEmptyEntries)),
                IMDB_ID = GetNodeText(node, "IMDB_ID"),
                Language = LanguageHome.GetByAbbreviation(GetNodeText(node, "Language")),
                Network = GetNodeText(node, "Network"),
                Overview = GetNodeText(node, "Overview"),
                Rating = GetNodeDouble(node, "Rating"),
                Runtime = GetNodeInt(node, "Runtime"),
                TVCOM_ID = GetNodeInt(node, "SeriesID"),
                Name = GetNodeText(node, "SeriesName"),
                Status = GetNodeText(node, "Status"),
                Banner = GetNodeText(node, "banner"),
                FanArt = GetNodeText(node, "fanart"),
                LastUpdated = lastUpdated,
                Zap2It_ID = GetNodeText(node, "zap2it_id")
            };
        }
        /// <summary>
        /// Gets the series by ID.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <param name="language">The language.</param>
        /// <returns></returns>
        internal static Series GetSeriesByID(int id, Language language) {
            Mirror mirror = MirrorHome.Get_Data();
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(mirror.MirrorPath + "/api/" + Settings.TheTVDBApiKey + "/series/" + id + "/all/" + language.Abbreviation + ".xml");
            return ParseSeriesNode(xmlDocument.SelectSingleNode("//Data/Series"));
        }
        #endregion

        #region Episodes
        /// <summary>
        /// Gets the episode by ID.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        internal static Episode GetEpisodeByID(int id, Language language) {
            Mirror mirror = MirrorHome.Get_Data();
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(mirror.MirrorPath + "/api/" + Settings.TheTVDBApiKey + "/episodes/" + id + language.Abbreviation + ".xml");
            return ParseEpisodeNode(xmlDocument.SelectSingleNode("//Data/Episode"));
        }

        /// <summary>
        /// Gets the episodes by series ID.
        /// </summary>
        /// <param name="seriesID">The series ID.</param>
        /// <param name="language">The language.</param>
        /// <returns></returns>
        internal static List<Episode> GetEpisodesBySeriesID(int seriesID, Language language) {
            Mirror mirror = MirrorHome.Get_Data();
            List<Episode> result = new List<Episode>();
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(mirror.MirrorPath + "/api/" + Settings.TheTVDBApiKey + "/series/" + seriesID + "/all/" + language.Abbreviation + ".xml");
            foreach (XmlNode node in xmlDocument.SelectNodes("//Data/Episode")) {
                result.Add(ParseEpisodeNode(node));
            }
            return result;
        }

        /// <summary>
        /// Parses the episode node.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <returns></returns>
        private static Episode ParseEpisodeNode(XmlNode node) {
            char[] splitChar = new char[] { '|' };
            DateTime firstAired;
            DateTime lastUpdated;
            if (!DateTime.TryParse(GetNodeText(node, "FirstAired"), out firstAired)) firstAired = DateTime.MinValue;
            if (!DateTime.TryParse(GetNodeText(node, "lastupdated"), out lastUpdated)) lastUpdated = DateTime.MinValue;
            return new Episode() {
                ID = GetNodeInt(node, "id"),
                GuestStars = new List<string>(GetNodeText(node, "GuestStars").Split(splitChar, StringSplitOptions.RemoveEmptyEntries)),
                AbsoluteNumber = GetNodeInt(node, "absolute_number"),
                Director = new List<string>(GetNodeText(node, "Director").Split(splitChar, StringSplitOptions.RemoveEmptyEntries)),
                DVDChapter = GetNodeText(node, "DVD_chapter"),
                DVDDiscID = GetNodeText(node, "DVD_discid"),
                DVDEpisodeNumber = GetNodeInt(node, "DVD_episodenumber"),
                DVDSeason = GetNodeInt(node, "DVD_season"),
                FileName = GetNodeText(node, "filename"),
                FirstAired = firstAired,
                IMDBID = GetNodeInt(node, "IMDBID"),
                Language = LanguageHome.GetByAbbreviation(GetNodeText(node, "Language")),
                LastUpdated = lastUpdated,
                Name = GetNodeText(node, "EpisodeName"),
                Number = GetNodeInt(node, "EpisodeNumber"),
                Overview = GetNodeText(node, "Overview"),
                ProductionCode = GetNodeText(node, "ProductionCode"),
                Rating = GetNodeDouble(node, "Rating"),
                SeasonID = GetNodeInt(node, "seasonid"),
                SeasonNumber = GetNodeInt(node, "SeasonNumber"),
                Writers = new List<string>(GetNodeText(node, "Writer").Split(splitChar, StringSplitOptions.RemoveEmptyEntries)),
                SeriesID = GetNodeInt(node, "seriesid")
            };
        }
        #endregion

        #region Private methods
        /// <summary>
        /// Gets the node text.
        /// </summary>
        /// <remarks>
        /// Returns empty string when the path is not found.
        /// </remarks>
        /// <param name="node">The node.</param>
        /// <param name="path">The path.</param>
        /// <returns>a string value</returns>
        private static string GetNodeText(XmlNode node, string path) {
            XmlNode n = node.SelectSingleNode(path);
            return n == null ? string.Empty : n.InnerText;
        }
        /// <summary>
        /// Gets the node double.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="path">The path.</param>
        /// <returns></returns>
        private static double GetNodeDouble(XmlNode node, string path) {
            string s = GetNodeText(node, path);
            return s == string.Empty ? double.MinValue : Convert.ToDouble(s);
        }
        /// <summary>
        /// Gets the node int.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="path">The path.</param>
        /// <returns></returns>
        private static int GetNodeInt(XmlNode node, string path) {
            string s = GetNodeText(node, path);
            return s == string.Empty ? int.MinValue : Convert.ToInt32(s);
        }
        #endregion
    }
}
